/*
    交换机相关类的定义：交换机类、交换机管理类
    1. 交换机类：对交换机的抽象描述
        属性：名称、类型、持久化标志、自动删除标志、其他参数
        方法：创建交换机、设置其他参数、获取其他参数
    2. 交换机管理类：对交换机数据进行管理以及持久化
        属性：数据库文件(交换机数据持久化的目标数据库文件)、交换机数据映射表(<交换机名, 交换机对象>)
        方法：声明交换机、删除交换机、获取交换机、判断交换机是否存在、销毁所有交换机数据
*/

#pragma once
#include "../common/logger.hpp"
#include "../common/helper.hpp"
#include "../common/message.pb.h"
#include <google/protobuf/map.h>
#include <string>
#include <unordered_map>
#include <mutex>
#include <memory>
#include <sstream>
#include <vector>


namespace mq
{
    // 交换机类
    struct Exchanger
    {
        Exchanger() {}
        Exchanger(const std::string& name, ExchangerType type, bool durable, bool auto_delete, const google::protobuf::Map<std::string, std::string>& args):  
            _name(name), _type(type), _durable(durable), _auto_delete(auto_delete), _args(args)
        {
        }

        // 获取其他参数: 将_args的值以"key=value&key=value"格式拼接成字符串返回
        std::string getArgs()
        {
            std::string ret;
            for(auto& e : _args)
            {
                ret += e.first + "=" + e.second + "&";
            }
            if(ret.size())
                ret.pop_back();
            return ret;
        }

        // 设置其他参数: 从args_str格式字符串中解析出_args的值
        void setArgs(const std::string& args_str)
        {
            std::vector<std::string> kvs;
            StringHelper::split(args_str, "&", kvs);
            for(auto& kv : kvs)
            {
                int pos = kv.find("=");
                std::string key = kv.substr(0, pos);
                std::string value = kv.substr(pos+1);
                _args[key] = value;
            }
        }

        std::string _name;   // 名称
        ExchangerType _type; // 类型
        bool _durable;       // 持久化标志
        bool _auto_delete;   // 自动删除标志
        google::protobuf::Map<std::string, std::string> _args; // 其他参数
        using ExchangerPtr = std::shared_ptr<Exchanger>;
    };

    // 交换机管理类
    class ExchangerManager
    {
    public:
        using ExchangerMap = std::unordered_map<std::string, Exchanger::ExchangerPtr>;
        using ExchangerManagerPtr = std::shared_ptr<ExchangerManager>;

    public:
        ExchangerManager(const std::string& db_file): _sqlite3_helper(db_file)
        {
            // 1. 打开交换机数据库文件, 如果不存在则创建
            std::string parent_dir = FileHelper::parentDir(db_file);
            if(!FileHelper::createDir(parent_dir))
                ERR_LOG("create dir %s failed\n", parent_dir.c_str());
            if(!_sqlite3_helper.open())
                ERR_LOG("open exchanger db %s failed\n", db_file.c_str());
            
            // 2. 创建交换机数据表
            createTable();

            // 3. 从数据库中恢复交换机数据
            _exchangers = recoveryAllExchangers();
        }

        // 声明交换机
        bool declareExchanger(const std::string& name, ExchangerType type, bool durable, bool auto_delete, const google::protobuf::Map<std::string, std::string>& args)
        {
            // 1. 判断交换机name是否存在
            std::unique_lock<std::mutex> lock(_mutex);
            if(_exchangers.count(name))
                return true;

            // 2. 创建交换机对象
            Exchanger::ExchangerPtr exchanger_ptr = std::make_shared<Exchanger>(name, type, durable, auto_delete, args);
            
            // 3. 插入数据
            // DBG_LOG("declare exchanger, name: %s, type: %d, durable %d\n", name.c_str(), type, durable);
            if(durable && !insertExchanger(exchanger_ptr)) // 持久化到数据库
            {
                ERR_LOG("declare exchanger %s failed\n", name.c_str());
                return false;
            }
            _exchangers[name] = exchanger_ptr; // 插入到映射表
            return true;
        }

        // 删除交换机
        void removeExchanger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchangers.find(name);
            if(it == _exchangers.end())
                return;
            if(it->second->_durable) // 从数据库中删除
                deleteExchanger(name);
            _exchangers.erase(it);
        }

        // 获取交换机
        Exchanger::ExchangerPtr getExchanger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchangers.find(name);
            if(it == _exchangers.end())
                return nullptr;
            return it->second;
        }

        // 判断交换机是否存在
        bool hasExchanger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _exchangers.count(name);
        }

        // 获取交换机个数
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _exchangers.size();
        }

        // 销毁所有交换机数据
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            deleteTable();
            _exchangers.clear();
        }

    private:
        /*
            交换机数据持久化到sqlite3数据库的相关操作
        */ 
        // 创建表：创建一张存放交换机数据的表 
        void createTable()
        {
            #define EXCHANGER_CREATE_TABLE_SQL "create table if not exists exchanger(name varchar(32) primary key, type int, durable int, auto_delete int, args varchar(1024))"
            if(!_sqlite3_helper.execute(EXCHANGER_CREATE_TABLE_SQL, nullptr, nullptr))
            {
                ERR_LOG("create table exchanger failed\n");
                abort();
            }
        }

        // 删除表
        void deleteTable()
        {
            #define EXCHANGER_DELETE_TABLE_SQL "drop table if exists exchanger"
            if(!_sqlite3_helper.execute(EXCHANGER_DELETE_TABLE_SQL, nullptr, nullptr))
            {
                ERR_LOG("drop table exchanger failed\n");
                abort();
            }
        }

        // 插入数据
        bool insertExchanger(const Exchanger::ExchangerPtr& exchanger_ptr)
        {
            if(exchanger_ptr == nullptr)
            {
                DBG_LOG("insert exchanger failed, exchanger_ptr is nullptr\n");
                return false;
            }
            std::stringstream sql;
            sql << "insert into exchanger(name, type, durable, auto_delete, args) values(";
            sql << "'" << exchanger_ptr->_name << "'," << exchanger_ptr->_type << ",";
            sql << exchanger_ptr->_durable << "," << exchanger_ptr->_auto_delete << ",";
            sql << "'" << exchanger_ptr->getArgs() << "');";
            // DBG_LOG("insert exchanger sql: %s\n", sql.str().c_str());
            if (!_sqlite3_helper.execute(sql.str(), nullptr, nullptr))
            {
                ERR_LOG("insert exchanger failed\n");
                return false;
            }
            return true;
        }

        // 删除数据
        void deleteExchanger(const std::string& exchanger_name)
        {
            std::stringstream sql;
            sql << "delete from exchanger where name = '" << exchanger_name << "';";
            if (!_sqlite3_helper.execute(sql.str(), nullptr, nullptr))
                ERR_LOG("delete %s exchanger failed\n", exchanger_name.c_str());
        }
        
        // 恢复数据: 从数据库表中恢复交换机数据到内存管理对象中
        ExchangerMap recoveryAllExchangers()
        {
            ExchangerMap exchanger_map;
            if(!_sqlite3_helper.execute("select * from exchanger;", selectCallback, &exchanger_map))
                ERR_LOG("get exchanger all failed\n");
            return exchanger_map;
        }

        // 回调函数：获取exchanger表中所有交换机数据时的回调
        static int selectCallback(void* arg, int col, char** values, char** files)
        {
            ExchangerMap* exchanger_map_ptr = reinterpret_cast<ExchangerMap*>(arg);
            Exchanger::ExchangerPtr exchanger_ptr = std::make_shared<Exchanger>();
            exchanger_ptr->_name = values[0];
            exchanger_ptr->_type = ExchangerType(std::stoi(values[1]));
            exchanger_ptr->_durable = std::stoi(values[2]);
            exchanger_ptr->_auto_delete = std::stoi(values[3]);
            exchanger_ptr->setArgs(values[4]);
            (*exchanger_map_ptr)[exchanger_ptr->_name] = exchanger_ptr;
            return 0;
        }

    private:
        ExchangerMap _exchangers; // 交换机映射表<名称，交换机对象>
        std::mutex _mutex;
        Sqlite3Helper _sqlite3_helper; // 交换机持久化操作句柄
    };
}
